TestController, Configuration of non SCPI devices
The program supports many different devices, not all uses SCPI, to handle them there are a some build in drivers that will translate between a simplified SCPI and the actual instrument protocol. Some of these drives are nearly fully hard coded, i.e. the device file basically list the name of the device, other can be configured with a device file.
For most of these drivers the only practical configuration that can be done without programing is declaring similar devices.
I will not be explaining most tags, see the SCPI configuration for more explanation.
Content
Single value
Binary DMM protocol
matchSpecification
Example
Modbus serial & network
Modbus register types
Commands to access the registers
Unsupported commands
Defining commands
Other commands
Modbus error codes
Definitions that uses this driver
Non-SCPI ascii devices (Ascii)
Commands to write and read values
Defining commands
Other commands
Skeleton example
Definitions that uses this driver
Non-SCPI ascii devices with binary envelope (AsciiBin)
Binary with fixed communication blocks (Block)
Commands to write and read values
Format specification
Defining commands
Checksum and CRC
Other commands
Configuration for streaming data
Configuration for polling data
Ascii variable length communication blocks, can be multi line ascii (AsciiBlock)
Configuration for streaming mode
Configuration for polled mode
Command mode
Format specification
Checksum and CRC
Other commands
Main page
Functions for use in calculator and definitions
Single value
This driver is for device that returns a single line with a single value on it. It can be something like this: "DC 45.3 mV" or "456.45".
The value can be returned at regular intervals or after a poll.
The first part is similar to SCPI definitions:
Code:
#idString first two parts of *idn? answer
#name The device name
#handle A short handle
#port The port used
#baudrate Baudrate for serial devices
#eol Used to change the standard LF end of line to CR or CRLF or disable with \_.
The id string must be constructed to look similar to real id strings, typical: "brand, brand model,"
To load this driver use:
Code:
#driver SingleValue
Next comes data type definition, either a single line without a selector or multiple lines with a selector matching the mode. Mode will be constructed from letters in the original line, start TestCOntroller in debug mode to see what it is for different modes.
A device with a single mode
Code:
#value Frequency Hz SI
Device with multiple modes
Code:
#value VoltageDC V d4 DCV
#value CurrentDC A si DCA
#value VoltageAC V d4 ACV
#value CurrentAC A si ACA
#value Resistance ohm si RESISTANCEOHM
Meters will usually use a text for error condition and may also use it for some other stuff.
Code:
#valueText value text
#valueText value "text"
;Examples:
#valueText OL OL
#valueText -OL "- OL"
#valueText 1 OPEN
It is possible to use OL or -OL as values. To include spaces in the text it must be in quotes.
The text is checked before checking for modes and if a match is found it is removed from the input before assembling the mode string.
The last entry is optional, it is only used if the device must be polled for the string:
It is possible to use escapes in the poll, i.e. \r for a return character or 0x17 for character 17 hex.
This poll will be combined with the #EOL value that has a default value of \n (i.e. a linefeed character). Defining "#eol \_" will disable the end of line character.
Example 1
Code:
#idString HKJ,HKJ Test
#name HKJ Test
#handle Test
#port comfixedbaud
#baudrate 1200
#eol \_
#driver SingleValue
#value VoltageAC V d5 ACV
#value VoltageDC V d5 DCV
#value Resistance V d5 RESISTANCEohm
#askValues \r
Example 2
Code:
#idString HKJ,HKJ Test
#name HKJ Test
#handle Test
#port comfixedbaud
#baudrate 1200
#driver SingleValue
#value Frequency Hz SI
For a complete example see the Protek506 definition file.
Binary DMM protocol
This protocol can handle fixed length binary data formats from a DMM, both with digits as Ascii values or as 7 segment values. It is part of the DMM2 and USBHIDDMM driver and is activated with:
Code:
#driver DMM2
#subDriver Definition
or
#driver USBHIDDMM
#subDriver Definition
The first definition is the data message format with the length and start detection bytes:
Code:
#dataFormat length firstByte firstByteMask
#dataFormat 15 0x02
#dataFormat 13 0x30 0xf0
#dataFormat 13 0 0
length specify the length in bytes.
firstByte is the first byte in the message.
firstByteMask is a mask to define what bytes to compare, (use 0xff for all bits and 0 to accept any byte). When missing 0xff is assumed.
For 7-segments displays the segments must be defined:
Code:
#segments stringWithA-F
#segments byteOfs stringWithA-F byteOfs stringWithA-F byteOfs stringWithA-F byteOfs stringWithA-F
#segments "....afe.....bgcd"
The stringWithA-F must be 8, 16, 24 or 32 characters long, depending on number of bytes used for each digit. Any character not in the A-F range is a unused position.
If the segments for the digits are non-sequential the second format must be used, any number of "byteOfs stringWithA-F" pairs can be specified and is numbered in sequence with the first one as digit 1.
If the display has a "1" digit that is outside the normal segment definition, use:
Code:
#addDigit digits matchSpecification
This will add the digits before the display reading. This is first done after decimal point processing.
The actual value is read with:
Code:
#digits byteOfs digits
#digits digit digits
#digits 1 5
byteOfs is how many bytes from the start of the data the digits starts.
digit is only used when the segment decoder contains the byteOfs (See #segments definition)
digits is the number of digits to read (Not the number of bytes). If lsb is first use a negative digit specification.
The sign is nearly always needed to show negative values, in some cases a overload flag must be used to reliable detect overload:
Code:
#sign matchSpecification
#overload matchSpecification
#sign b(7,"xxxxx1xx")
#overload b(7,"xxxxxxx1")
The above number do not contain any decimal point or adjustment for range, this is done with:
Code:
#point digit matchSpecification
#point 3 b(9, "xxxxxxx1")
#point 2 b(7,"xxxxxxx1")
#point 1 b(5,"xxxxxxx1")
When used there will usually be multiple of these specifications, but often one or two less than there are digits.
This specification is usually only used for 7-segment coding, not for ascii coding.
In addition to the decimal point a multiplier must be used to adjust the number:
Code:
#point factor matchSpecification
#mult M b(11, "xxxxxx1x")
#mult k b(11, "xxxxxxx1")
#mult m b(13, "xxxxxxx1")
#mult 1e0 v(0,0x30)
#mult 1e1 v(0,0x31)
#mult 1e2 v(0,0x32)
The factor is either a SI prefix, matching the segment on the display or just a numeric factor.
Next the range or mode must be defined:
Code:
#range mode
#range - matchSpecification
#range mode matchSpecification
#range mode /factor matchSpecification
#range mode *factor matchSpecification
#range Ohm b(12, "xxxxx10x")
#range F b(13, "xxxxx1xx")
#range F /1e12 v(6,0x36)
#range - !b(12, "00001101")
#range - b(14, "xxxxx11x") | !b(14, "1110xxxx")
mode is a string matching the internal mode table, it can be one of V A F Ohm Hz % TempC TempF %mA dB dBm W VA VAR Wh
factor is either multiplied or divided with the display value and is typically used for ascii formats.
A range without a matchSpecification sets a default range or mode for the driver, this is useful when starting on a specification, but is best removed when finished.
The mode = - is a stop specification (No value is decoded) and is used to block invalid messages or states.
All the modes are tested in the specified sequence and the testing will stop at the first match.
In addition to the above there is AC/DC specifications, they are added to the above modes when present:
Code:
#rangeAC matchSpecification
#rangeDC matchSpecification
#rangeDC b(10,"xxxx1xxx")
#rangeAC b(10,"xxxxx1xx")
They only work for modes where a AC/DC/ACDC mode is relevant (V A W Wh).
With the above most multimeters will work, but some chips have a few special issues that cannot be handled with that easily.
Some issues are handled automatic:
dBm: When #range is "dB" and #mult is 1e-3 or m the dB range will change to dBm
%: The minus flag is ignored
Hz: The minus flag is ignored
TempF: A conversion to Celsius is performed.
For anything else a script can be added to a range/mode:
Code:
#modify1 matchSpecification
#modify2 matchSpecification
#modify range expression
#modify VAC (mult==1)?value/1e5:value
#modify Hz (mult>5)?value/10:value
To handle this it is possible to use expressions to process the value. The modify1/2 is optional flags.
There are some variables:
value: The value with decimal point (from #point) placed.
mult: The multiplier made from #range & #mult specifications.
modify1: Result from #modify1
modify2: Result from #modify2
matchSpecification
This specification will return true or false, depending on if it matches the specified bytes or not. There are a couple of different formats, the "b" is the basic format, the other formats are for convenience.
Code:
b(byteOfs,bitmask)
s(byteOfs,segmentList)
c(byteOfs,character)
v(byteOfs,value)
b(14, "xxxxx01x")
s(9,"adef")
c(9,"C")
v(6,0x3d)
byteOfs is the offset into data
bitmask is 0/1 bits, any other character will assume a do not care position. It must have exactly 8 characters
segmentList is a list of segments to be on in a digit, i.e. letters from A to F
character will match a ascii character, with 7-segment only "0-9, L E F C r" is recognized
value is a integer value either in decimal or hex and must match the full byte.
The result from a matchSpecification can be inverted with a ! in front of it, this will not affect matchSpecification after this one:
It is possible to chain multiple matchSpecification on a line:
Code:
b(14, "xxxxx01x") & s(9,"adef")
b(14, "xxxxx01x") | s(9,"adef")
& means both must be true
| means at least one of them must be true.
Example
Download some examples in a zip file
These are complete definitions matching the internal hard coded definition.
Modbus serial & network
Modbus is a packet based interface, with a couple of fixed formats based in a hardware model with different types of input/output.
This protocol is build on top of SCPI and requires all the stuff that a normal SCPI definition does, in addition to a couple of #scpiCmd definitions.
Modbus register types
Register can be read/write or read only types, this is (hopefully) listen in the device manual.
The 4 different types of registers do not necessarily share address space, i.e. the same address can be different things in the different register types.
- Coil: These registers are bit registers, it is possible read one or many bits at a time, but only one can be written at a time.
- Discrete input: Bit registers, these can be read one or many bits at a time, but not written.
- Input register: Register that uses 16 bit (word) data, these can be read one or many words at a time, but not written.
- Holding register: Register that uses 16 bit (word) data, these can be read or written one or many words at a time.
It is common to combine holding registers to 32 bit data as long or float values.
Commands to access the registers
These commands can be used directly from the command line, but this is mostly for test.
- Coil address value
- Coil? address {bits}
- dInput? address {bits}
- holding address value {moreValues...} {*factor or /factor }
- holding? address {{words} *factor or /factor or &mask}
- holdingS? address {{words} *factor or /factor}
- input? address {{words} *factor or /factor or &mask}
- holdingL address value {moreValues...} {*factor or /factor}
- holdingL? address {{doubleWords} *factor or /factor}
- holdingSL? address {{doubleWords} *factor or /factor}
- holdingF address value {moreValues...} {*factor or /factor}
- holdingF? address {{floats} *factor or /factor}
- holdingBytes? address {words}
- unitId id
The Coil? & dInput? will return all bits in a single number, the other command will return a list of values.
The address can be in decimal or in hex by prefixing with 0x
Reading commands has a optionally count, when not specified one value is read, when specified it defines how many values to read.
The L, SL and F prefix works with 32 bit values for either unsigned integers, singed integer or floats.
The *factor or /factor is used to scale the values, i.e. use /10 to divide by 10 or *10 to multiply by 10
The &mask can be used to remove undefined bits and can be something like "&0xff" to only return 8 bits from the 16 bit answer
The unitId command only works for modbus TCP and will set the unit identifier.
The holdingBytes? uses return the a string with all data bytes from the answer that can be typecast to bytes and must be processed with a :readmath:
Unsupported commands
Do not expect a device to support all the different register access commands, not all registers may be implemented and writing may be restricted to 1 or many registers.
Because TestController automatic select between single and multi register write, there will be a problem with devices not supporting single write (A single write can be simulated with a multi write where the count is 1). To force TestController into always using multi write use this define in the definition file:
Code:
#disableWriteSingle 1
Defining commands
The above commands are only supposed to be used for defining other commands with. By defining commands it makes the definition easier to read and it also makes it easier to directly give commands on the command line.
The format is fairly simple:
Code:
#scpiCmd name register access command with parameters
;Examples:
#scpiCmd Current holdingF 0xa01 (value)
#scpiCmd Current? holdingF? 0xa01
Use (value) to insert parameters from the "name" command. It is possible to use value multiple times and it is also possible to use an expression inside the brackets.
If a value needs to be carried between scpiCmd it can be saved with a ":setvar:" tag
Code:
;Save input value
#scpiCmd mode holding 0xa00 (value)
:setvar: currentMode=value
;Save answer
#scpiCmd mode? holding? 0xb04 1 &0xff
:setvar: currentMode=value
;Using the saved value
#scpiCmd on holding 0xa00 (currentMode);holding 0xa00 (getElement("43 42",value))
It is important that this variable is created before it is used. To do this use a command in "#initCmd" that has a :setVar: for the variable.
Other commands
A few more commands are supported.
To verify it is the correct device that is connected use this command. Often it is possible to read a model number from the device and compare that to the value.
Code:
#verifyDevice value commandToGetvalue
;Example, note mode? is defined with "#scpiCmd model? holding? 0xb06" (I could have used the holding? directly).
#verifyDevice 2 model?
The software always ask for serial number and software versions when connecting to a device, by defining these two command they will be read:
Code:
#scpiCmd getDeviceSW? ...
#scpiCmd getDeviceSN? ...
Not all devices can handle a steady communication, some needs a small delay between each message to work correctly. This is done with this optional setting:
Code:
#cmdDelayTime time in ms
;Example
#cmdDelayTime 50
The standard modbus driver is RTU, but it can be switched to the TCP driver with:
Code:
#subDriver TCP
#subDriver RTU// Is also valid, but not needed
#subDriver Kunkin// Kunkin modbus format including swapped crc bytes
#subDriver Kunkinx// Kunkin modbus format, used in newer versions of the Kunkin software
#subDriver Ascii
When using modbus TCP the #port will usually need to be defined as "#port 502"
Modbus error codes
TestController will return error codes as negative value, i.e. -1 is error 1.
- 1: Illegal Function
- 2: Illegal Data Address
- 3: Illegal Data Value
- 4: Slave Device Failure
- 5: Acknowledge
- 6: Slave Device Busy
- 7: Negative Acknowledge
- 8: Memory Parity Error
- 10: Gateway Path Unavailable
- 11: Gateway Target Device Failed to Respond
Definitions that uses this driver
The power supply definitions RidenRD6006 uses this driver. It has a fairly advanced configuration menu.
Maynuo M97xx definition is a electronic load.
Non-SCPI ascii devices (Ascii)
This interface will work with devices that requires strings of ascii commands, but are not SCPI compliant. It works in a similar way to the Modbus definition.
This protocol is build on top of SCPI and requires all the stuff that a normal SCPI definition does, in addition to a couple of #scpiCmd definitions.
Commands to write and read values
These commands can be used directly from the command line, but this is mostly for test.
- tx cmd - Send the cmd to the device, do not expect any answer.
- txrx cmd - Send the cmd to the device, waits for an answer, but do not return the answer.
- txrx? cmd - Send the cmd to the device, waits for an answer and returns the answer.
- txrx2? cmd - Send the cmd to the device, waits for a two line answer and returns the answer.
- txrn? lines cmd - Send the cmd to the device, waits for a multi line answer and returns the answer.
- rxuntil? expression - Receive until expression is true, last received data is in "value"
- rxalluntil? expression - Receive until expression is true, all received data is in "value"
- txBin cmd This command will send a string without the default line termination character(s) and will not expect an answer.
- txrx1Bin? cmd This command will send a command and then read one answering byte, result is returned as a number.
- txrxnBin? cnt cmd This command will send a command and then read cnt answering byte, result is returned as a number for up to 8 characters and a bytes string for more characters.
- txrx1Bin cmd This command will send a command and then read one answering byte, no result is returned
- txrxnBin cnt cmd This command will send a command and then read cnt answering byte, no result is returned
- none Dummy write command, used together with ":servar: variableName=inputValue" to save something.
- none? Dummy read command, used to read a variable from :setvar: with a ":readmath: variableName"
In a #scpiCmd definition the ; is transmitted directly.
The Bin commands do not use specified EOL format, it must be included in the cmd (See escape codes below).
It is very important to use command that waits for an answer, if the cmd will return an answer.
Escape codes for bin commands: \b \t \n \r \\ \" \' \u0000 \x00, \u is followed by a four digit unicode hex value, \x is followed by a two digit hex code.
Defining commands
The above commands are only supposed to be used for defining other commands with. By defining commands it makes the definition easier to read and it also makes it easier to directly give commands on the command line.
The scpiCmd has shares a common context, this means it is possible to use :setvar: and then reference to the variable in another #scpiCmd.
The format is fairly simple:
Code:
#scpiCmd name tx cmd
#scpiCmd name txrx cmd
#scpiCmd name? txrx? cmd
#scpiCmd name? txrx? cmd
#scpiCmd name? txrx2? cmd
#scpiCmd name? txrxn? lines cmd
#scpiCmd name? txrxnBin? bytes cmd
#scpiCmd name? txrx1Bin? cmd
#scpiCmd name txrxnBin bytes cmd
#scpiCmd name txrx1Bin cmd
#scpiCmd name tx cmd (value)
#scpiCmd name txrx cmd (value)
#scpiCmd name? txrx? cmd (value)
Use (value) to insert parameters from the "name" command. It is possible to use value multiple times and it is also possible to use an expression inside the brackets.
On the :readmath: and :setVar: tags a valueInput can be used to access the this value, the "value" parameter will show the return value.
A number or n in the command lines means multiple lines, except with bin where it means bytes (Up to 8, answer is return as a number).
If a value needs to be carried between scpiCmd it can be saved with a ":setvar:" tag
Code:
;Save input value
#scpiCmd name tx (value)
:setvar: currentMode=value
;Save answer
#scpiCmd name? txrx? cmd
:setvar: currentMode=value
;Using the saved value
#scpiCmd name tx (currentMode)
It is important that this variable is created before it is used. To do this use a command in "#initCmd" that has a :setVar: for the variable.
Other commands
A few more commands are supported.
To verify it is the correct device that is connected use this command. Often it is possible to read a model number from the device and compare that to the value.
Code:
#verifyDevice value commandToGetvalue
;Example, note model? must defined with "#scpiCmd model?
#verifyDevice 2 model?
The software always ask for serial number and software versions when connecting to a device, by defining these two command they will be read:
Code:
#scpiCmd getDeviceSW? ...
#scpiCmd getDeviceSN? ...
Not all devices can handle a steady communication, some needs a small delay between each message to work correctly. This is done with this optional setting:
Code:
#cmdDelayTime time in ms
;Example
#cmdDelayTime 50
Skeleton example
Use the below skeleton when starting a new definition.
Code:
#idString brand,brand model
#name brand model
#handle mostlyModel
#driver Ascii
; port can be com, comfixedbaud, comnobaud or a port number for network devices.
#port 5025
; Baudrate definition is needed for comfixedbaud types.
;#baudrate 9600
; The author statement is used for the listing in the About window.
;#author you name or handle
; There must be a line for each of the original device commands that will be used, converting it to a similar SCPI command
;#scpiCmd init tx command to init
;#scpiCmd values? txrx? command to read current value or values. It is possible to define value1?, value2?, etc. and then use them all with a ; between in the #askValues statement.
; A list of possible column name with unit and formatter (SI, Time, Int, D0..D6)
#value Voltage V SI
; Use these commands to get a full id line and prevent connection to other devices
;#verifyDevice value commandToGetvalue
;#scpiCmd getDeviceSW? ...
;#scpiCmd getDeviceSN? ...
; This is a single line command
#askValues values?
;Accept this delay when reading values (seconds)
#readingDelay 5
; Prepare the meter to response to #askValues
;#prepareSample
; Initial commands to meter when establishing connection
;#initCmd
; Final command to meter before breaking connection
;#finalCmd
; Used when output off button is pressed
;#outputOff
Definitions that uses this driver
FeelElecFY6x00-xxM defines many ARB models using this driver.
HP3478A is a device from before SCPI.
Non-SCPI ascii devices with binary envelope (AsciiBin)
This driver is very similar to the ascii driver, but will handle a binary envelope around the messages. It supports the same definitions as the ascii driver, with the addition that a packet format must be specified.
Code:
#driver AsciiBin
#packetFormat name
The supported packet format (envelope) names are:
- Length7: Prefix message with a length byte where bit 7 is 1. The length byte is not included in the length count.
- Length15: Prefix message with two length byte (msb first) where bit 15 is 1. The length bytes is not included in the length count.
- Length31: Prefix message with four length byte (msb first) where bit 31 is 1. The length bytes is not included in the length count.
Note: txrxn? and txrx2? is not supported.
Binary with fixed communication blocks (Block)
This driver can handle binary protocols with fixed length messages, it is possible to extract one or more values from each message.
Commands to write and read values
These commands can be used directly from the command line, but this is mostly for test.
- tx byteSequence - Send the byte sequence, no answer is expected
- txrx1 byteSequence - Send the byte sequence, 1 byte answer is expected, but is not returned from the driver.
- txrx2 byteSequence - Send the byte sequence, 2 byte answer is expected, but is not returned from the driver.
- txrxn count byteSequence - Send the byte sequence, count byte answer is expected, but is not returned from the driver.
- txrx1? byteSequence {/ format}- Send the byte sequence, 1 byte answer is expected and returned
- txrx2? byteSequence {/ format}- Send the byte sequence, 2 byte answer is expected and returned
- txrxn? count byteSequence {/ format}- Send the byte sequence, count byte answer is expected and returned
byteSequence is a list of numbers, both decimal and hex is accepted.
/ when present will disable the default unsigned integer conversion and expect format specifiers instead.
format makes it possible to interpret the answer as any data type and can handle more than 8 bytes.
It is very important to use command that waits for an answer, if the cmd will return an answer.
These commands are not used with streaming data.
Format specification
One or more formats can be specified and each will return a number/string. The general format is:
byteIndex dataType bytes {multiplier} {offset}
All elements must be combined without any space between.
- byteIndex: Index into the answer, first byte is index 0
- dataType: Type of data and modifiers:
- i: Signed integer, can be from 1 to 8 bytes long. lsb is first (See r).
- u: Unsigned integer, can be from 1 to 8 bytes long. lsb is first (See r).
- a: Ascii integer, i.e. a number in plain ascii, any non-numeric character is ignored, except -
- e: Ascii float/exponent, i.e. a number in plain ascii with a point and or exponent, can be with leading spaces or zeros and may contain a sign.
- h: Hex, a number in hex, leading spaces are ignored and a sign can be present
- f: Floating point, can be either 4 or 8 bytes long. lsb is first (See r).
- d: Binary coded decimal, can be 1 to 9 bytes long. msb is first (See r, n & !).
- s: String, no length restriction, assumed to be ISO8859-1 (Similar to US ASCII but for 8 bits characters).
- b: Bit, test if a single bit is 0 or 1, the bytes specifications is a bit no specification and ! will invert the bits.
- #: Put bytes back into byte list, used with r modifier to handle special byte sequences. Only use when no other solution.
- m: Will set a minus value for next integer read (iuahd), the bytes is in hex format and is used as a mask and compare value, i.e. 4m44 or 4mff44 will set a minus sign if pos 4 contains 44.
- z: Must be used after one of the above (Only iud) and will zero the msb bit, up to 8 z's can be used.
- r: Must be used after one of the above and will swap the byte sequence. Used to handle endianness.
- !: Must be used after one of the above and will invert the bits, useful for BCD and b formats.
- x: Must be used after one of the above and will reverse bits in each byte.
- n: Must be used after one of the above and will swap nipples, may be needed together with r for BCD with lsb first.
- bytes: Number of bytes, each data type has some restrictions.
- multiplier: Either multiply or divide with a factor, use *number or /number
- offset: Either add or subtract a offset, use +number of -number
There is no restriction on rxnz! modifiers, but there is only a few combinations that are useful.
Some examples:
- 3i2: Signed integer at byte 3 and 4, 3 is lsb
- 3ir2: Signed integer at byte 3 and 4, 4 is lsb
- 0u1: Unsigned integer at byte 0
- 2s5: String in byte 2, 3, 4, 5 and 6, byte 2 is first character in string.
- 4f4: Floating point number in byte 4, 5, 6 and 7. Byte 4 is lsb
- 4fr4: Floating point number in byte 4, 5, 6 and 7. Byte 7 is lsb
- 1i3/10: Signed integer in byte 1, 2 and 3, value is divide by 10.
- 1i3*2+3: Signed integer in byte 1, 2 and 3, value is multiplies by 2 and 3 is added to the result.
- 1b3: Return 1 if bit 3 in byte 1 is 1, it may often be better to return a full byte or more and do the bit checking in a :readmath: statement.
- 1b!3: Return 1 if bit 3 in byte 1 is 0
The function makeDouble() can be used in a #askValuesMathFormat or :readmath: to assemble double numbers from a couple of integer values.
Defining commands
The above commands are only supposed to be used for defining other commands with. By defining commands it makes the definition easier to read and it also makes it easier to directly give commands on the command line.
The format is fairly simple:
Code:
#scpiCmd name tx byteSequence
#scpiCmd name txrx1 byteSequence
#scpiCmd name txrx2 byteSequence
#scpiCmd name txrxn count byteSequence
#scpiCmd name? txrx1? byteSequence {/ format}
#scpiCmd name? txrx2? byteSequence {/ format}
#scpiCmd name? txrxn? count byteSequence {/ format}
Use (value) to insert parameters from the "name" command, each () must return a byte sized value. It is possible to use value multiple times and it is also possible to use an expression inside the brackets.
If a value needs to be carried between scpiCmd it can be saved with a ":setvar:" tag
Checksum and CRC
The driver supports adding a checksum or CRC to the transmitted messages, this is done with:
Code:
#checksum type addFormat firstByte initValue poly xor
#checksum crc16 binhl 0 0 0x8005 0
#checksum crc16r binhl 0 0 !0x8005 0
type can be one of: crc8, crc8r, crc16, crc16r, crc32, crc32r, sum8, sum16, msum8, msum16, xor8
addFormat can be one of: binhl, binlh, hexhl, hexlh (hl/lh is ignored for 8 bit values)
firstByte is first byte to include in calculation, this is often 0
initValue is the initial value of the check, this is often 0 of 0xffff
poly is the actual CRC polynomial, prefix with ! to reflect it.
xor A non zero value will invert bits in the specified positions in the final result.
The formats with r (i.e. crc16r) is reflected version and must be used with the reflected version of the polynomial
For poly values see https://crccalc.com/ To get values where refIn & refOut is true use the r version and place a ! before the polynomial
Other commands
A few more commands are supported.
To verify it is the correct device that is connected use this command. Often it is possible to read a model number from the device and compare that to the value.
Code:
#verifyDevice value commandToGetvalue
;Example, note model? must defined with "#scpiCmd model?
#verifyDevice 2 model?
The software always ask for serial number and software versions when connecting to a device, by defining these two command they will be read:
Code:
#scpiCmd getDeviceSW? ...
#scpiCmd getDeviceSN? ...
Not all devices can handle a steady communication, some needs a small delay between each message to work correctly. This is done with this optional setting:
Code:
#cmdDelayTime time in ms
;Example
#cmdDelayTime 50
To always add some bytes to the end of the message, this is added after any checksum.
Configuration for streaming data
For devices that sends a data message at regular intervals use these tags to configure the Block driver for it.
Code:
#rxStart initial bytes in messages
#rxEnd Final bytes in message, this can be used instead of #rxStart
#rxLength number of bytes in message including initial bytes
#rxFormat format, see "Format specification"
#askValues values?// Must use "values?", it is possible to add #askValuesMathFormat to do further processing of the values
#pollPause delay// Delay in milliseconds between polls, default is 50ms
#rxStart \x0241// This is the initial bytes: 0x02 0x34 0x31
#rxLength 64
#rxFormat 8i4 12i4
Configuration for polling data
To poll a device at regular intervals for data, use these tags to configure the Block driver for it.
Code:
#rxStart initial bytes in messages
#rxEnd Final bytes in message, this can be used instead of #rxStart
#rxLength number of bytes in message including initial bytes
#rxFormat format, see "Format specification"
#poll byteSequence, will send this message at regular intervals. This must be all bytes for the poll, no checksum or eol is added.
#askValues values?// Must use "values?", it is possible to add #askValuesMathFormat to do further processing of the values
#rxStart \x0241// This is the initial bytes: 0x02 0x34 0x31
#rxLength 64
#rxFormat 8i4 12i4
#poll "send"
Ascii variable length communication blocks, can be multi line ascii (AsciiBlock)
This driver can handle Ascii protocols with variable length messages, received data is filtered with a regular expression. The driver has 3 operating modes, they are streaming, polled and command.
Configuration for streaming mode
For devices that sends a data message at regular intervals use these tags to configure the AsciiBlock driver for it. Communication is done in the background.
This driver uses the binary communication drivers, this avoids any inherited dependence on CR and LF characters.
Code:
#rxStart initial bytes in messages, this can be empty, but this may make the communication unstable.
#rxEnd final bytes in message, can be \r\n
#rxCount number of times to receive #rxEnd, i.e. number of lines for a multiline ascii, when missing 1 is assumed.
#rxFormat format, see "Format specification"
#askValues values?// Must use "values?", it is possible to add #askValuesReadFormat and #askValuesMathFormat to do further processing of the values
#rxStart Da:
#rxEnd \r\n\r\n
#rxFormat .*?([0-9.E+-]+).*?([0-9.E+-]+).*?([0-9.E+-]+)
#askValues Values?
#askValuesReadFormat can be useful for filtering the result from #rxFormat
The #rxEnd activate background mode as either streaming or polled mode.
Configuration for polled mode
Polled mode works nearly the same as streaming mode, except a poll must be send to get the data. Communication is done in the background.
Code:
#rxStart initial bytes in messages.
#rxEnd final bytes in message, can be \r\n
#rxCount number of times to receive #rxEnd, i.e. number of lines for a multiline ascii, when missing 1 is assumed.
#poll String to request data, the specification of poll must include any required CR, LF or other characters
#rxFormat format, see "Format specification"
#askValues values?// Must use "values?", it is possible to add #askValuesReadFormat and #askValuesMathFormat to do further processing of the values
#rxStart Da:
#rxEnd \r\n\r\n
#poll data?
#rxFormat .*?([0-9.E+-]+).*?([0-9.E+-]+).*?([0-9.E+-]+)
#askValues Values?
#askValuesReadFormat can be useful for filtering the result from #rxFormat
The #rxEnd activate background mode as either streaming or polled mode.
Command mode
In this mode commands must be send and answers to these received. These commands can be used directly from the command line, but this is mostly for test.
The command will work in any mode, but are best used only in command mode, in streaming mode they may fail, due to the background communication.
These commands are generally used together with #scpiCmd
- tx cmd - Send the sequence, no answer is expected
- txrx1 cmd /format - Send the sequence, 1 block/line answer is expected, but is not returned from the driver.
- txrx2 cmd /format - Send the sequence, 2 block/line answer is expected, but is not returned from the driver.
- txrxn count cmd /format - Send the sequence, count block/line answer is expected, but is not returned from the driver.
- txrx1? cmd /format - Send the sequence, 1 block/line answer is expected and returned.
- txrx2? /format - Send the sequence, 2 block/line answer is expected and returned.
- txrxn? count /format - Send the sequence, count block/line answer is expected and returned.
cmd is a ascii string
/ is followed by a regular expression, see format below.
It is very important to use command that waits for an answer, if the cmd will return an answer.
Some other tags that can be useful:
#rxEol string - This is delimiter for received blocks/lines, when not specified default is \r\n
#eol string - Adds this string to all transmitted commands (Except #poll), when not specified default is \r\n
#charset charset - override default ISO-8859-1 charset specification
#cmdDelayTime milliseconds - minimum time between commands
#checksum type - Add a checksum to the messages
#askValuesReadFormat numberhandling - Can be used to remove some numbers from the regex result
Format specification
The format is a regular expression where all groups are returns as answer. Due to the complexity of regEx there is a shortcut method to generate the necessary expression.
Using regular expressions
To way to extract numeric results is to use the following regEx:
for each number in the answer, i.e. a answer with 3 numbers will use:
Code:
.*?([0-9.E+-]+).*?([0-9.E+-]+).*?([0-9.E+-]+)
to decode all 3 numbers (This is a simplified regEx to match a number and will match some non-numeric items)
A short explanation:
- .* Means any string of characters
- .*? Means any string of characters, but only until next element in the expression matches.
- () Defines a group and it is anything inside these groups that TestController will use.
- []+ Means 1 or more of the characters listed inside the brackets.
- 0-9 Means all characters from 0 to 9, i.e. 0 1 2 3 4 5 6 7 8 9
- .E+- Is other characters used in floating point numbers (- must be placed last or it will signal a sequence)
- [0-9.E+-]+ Is any string of characters used in a floating point number, first character not matched will stop this search.
More complex regex expression can be used for a more precise filter. See Java documentation for a explanation of all the elements that can be used in a regular expression.
The format cannot be specified on the command line, because a ( will switch to calculator mode, there is a way around that that can be used when testing.
Define the command including format as a variable, then use the calculator mode to return the command.
Code:
=var cmd="txrxn? 2 cmd / .*?([0-9.E+-]+).*?([0-9.E+-]+).*?([0-9.E+-]+)
(cmd)
Using the simplified way
Instead of the above it is possible to build a similar regEx with a few letters, this method works when the format do not contain any parentheses.
Use one of the letters:
- f F u U: to return a number (RegEx used: .*?([+-]?[0-9]+[.]?[0-9]*E?[+-]?[0-9]*)).
- x X: to skip a number (RegEx used: .*?[+-]?[0-9]+[.]?[0-9]*E?[+-]?[0-9]*).
- s S: to return a number with optional SI prefix (pnumkMG) (RegEx used: .*?([+-]?[0-9]+[.]?[0-9]*[pnumkMG]?)).
This matches the letters used in #askValuesReadFormat
This means a format with "fxf" will return the first and third number and skip the second.
Checksum and CRC
The driver supports adding a checksum or CRC to the transmitted messages, this is done with:
Code:
#checksum type addFormat firstByte initValue poly xor
#checksum crc16 binhl 0 0 0x8005 0
#checksum crc16r binhl 0 0 !0x8005 0
type can be one of: crc8, crc8r, crc16, crc16r, crc32, crc32r, sum8, sum16, msum8, msum16, xor8
addFormat can be one of: binhl, binlh, hexhl, hexlh (hl/lh is ignored for 8 bit values)
firstByte is first byte to include in calculation, this is often 0
initValue is the initial value of the check, this is often 0 of 0xffff
poly is the actual CRC polynomial, prefix with ! to reflect it.
xor A non zero value will invert bits in the specified positions in the final result.
The formats with r (i.e. crc16r) is reflected version and must be used with the reflected version of the polynomial
For poly values see https://crccalc.com/ To get values where refIn & refOut is true use the r version and place a ! before the polynomial
Other commands
A few more commands are supported.
To verify it is the correct device that is connected use this command. Often it is possible to read a model number from the device and compare that to the value.
Code:
#verifyDevice value commandToGetvalue
;Example, note model? must defined with "#scpiCmd model?
#verifyDevice 2 model?
The software always ask for serial number and software versions when connecting to a device, by defining these two command they will be read:
Code:
#scpiCmd getDeviceSW? ...
#scpiCmd getDeviceSN? ...